package com.hh.generator.service;

import cn.hutool.core.io.FileUtil;
import com.hh.generator.common.dto.ColumnEntity;
import com.hh.generator.common.dto.TableEntity;
import com.hh.generator.common.mapper.SysGeneratorMapper;
import com.hh.generator.common.properties.GeneratorProperties;
import com.hh.generator.core.generator.*;
import com.hh.generator.core.model.Config;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @Date 2020-06-08 14:03
 **/
@Service
public class GeneratorService {

    public static Properties PROP = new Properties();

    static {
        PROP.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
        Velocity.init(PROP);
    }

    @Autowired
    private GeneratorProperties properties;
    @Autowired
    private SysGeneratorMapper sysGeneratorMapper;

    @PostConstruct
    public void run() {
        Config config = new Config();
        config.setModule(properties.getModule());
        config.setTablePrefix(properties.getClassConfig().getTablePrefix());
        config.setBasePackage(properties.getBasePackage());
        config.setMethods(properties.getClassConfig().getMethods());
        config.setSpringApplicationName(properties.getClassConfig().getSpringApplicationName());
        config.setFacadeBasePath(properties.getClassConfig().getFacadeBasePath());
        config.setControllerBasePath(properties.getClassConfig().getControllerBasePath());
        config.init();
        if (properties.getAppendMethod()) {
            genMethod();
        } else {
            genNewTables(config);
        }
    }

    private void genNewTables(Config config) {
        FileUtil.del(getTargetPath() + "generate");
        for (String table : properties.getClassConfig().getTables()) {
            if (StringUtils.isBlank(table)) {
                continue;
            }
            TableEntity tableEntity = sysGeneratorMapper.queryTable(properties.getClassConfig().getSchema(), table);
            List<ColumnEntity> columnEntities = sysGeneratorMapper.queryColumns(properties.getClassConfig().getSchema(), table);
            gen(new EntityGenerator(config, tableEntity, columnEntities), "entity");
            gen(new MapperGenerator(config, tableEntity, columnEntities), "mapper");
            gen(new MapperXmlGenerator(config, tableEntity, columnEntities), "mapperXml");
            gen(new ServiceGenerator(config, tableEntity, columnEntities), "service");
            gen(new ServiceImplGenerator(config, tableEntity, columnEntities), "serviceImpl");
            gen(new ConverterGenerator(config, tableEntity, columnEntities), "converter");
            gen(new FacadeImplGenerator(config, tableEntity, columnEntities), "feignImpl");
            gen(new FacadeGenerator(config, tableEntity, columnEntities), "feign");
            gen(new InfoGenerator(config, tableEntity, columnEntities), "info");
            gen(new QueryRequestGenerator(config, tableEntity, columnEntities), "queryRequest");
            gen(new AddRequestGenerator(config, tableEntity, columnEntities), "addRequest");
            gen(new AddResponseGenerator(config, tableEntity, columnEntities), "addResponse");
            gen(new UpdateRequestGenerator(config, tableEntity, columnEntities), "updateRequest");
            gen(new UpdateResponseGenerator(config, tableEntity, columnEntities), "updateResponse");
            gen(new DeleteResponseGenerator(config, tableEntity, columnEntities), "deleteResponse");
            EnumGenerator enumGenerator = new EnumGenerator(config, tableEntity, columnEntities);
            Map<String, String> enums = enumGenerator.generateEnums();
            enums.forEach((fileName, content) -> {
                gen(fileName, content, "enums");
            });
            gen(new ControllerGenerator(config, tableEntity, columnEntities), "controller");
        }
    }

    private void genMethod() {
        GeneratorProperties.MethodConfig methodConfig = properties.getMethodConfig();
        MethodGenerator methodGenerator = new MethodGenerator(methodConfig.getReturnType(), methodConfig.getModel(), methodConfig.getAction());
        String fileName = getFile("controller", methodConfig.getController());
        String content = methodGenerator.generatorMethod("controller");
        appendMethod(fileName, content);
        fileName = getFile("feign", methodConfig.getFacade());
        content = methodGenerator.generatorMethod("feign");
        appendMethod(fileName, content);
        fileName = getFile("feignImpl", methodConfig.getFacade() + "Impl");
        content = methodGenerator.generatorMethod("feignImpl");
        appendMethod(fileName, content);
        fileName = getFile("service", methodConfig.getService());
        content = methodGenerator.generatorMethod("service");
        appendMethod(fileName, content);
        fileName = getFile("serviceImpl", methodConfig.getService() + "Impl");
        content = methodGenerator.generatorMethod("serviceImpl");
        appendMethod(fileName, content);
    }

    private String getFile(String type, String name) {
        return properties.getCodePathMap().get(type) + "/" + name + ".java" + (properties.getMethodConfig().getAppend() ? "" : ".copy");
    }

    private void gen(AbstractTableBaseGenerator generator, String path) {
        gen(generator.fileName(), generator.generate(), path);
    }

    private void gen(String filename, String content, String path) {
        if (CollectionUtils.isNotEmpty(properties.getClassConfig().getGenerateList()) && !properties.getClassConfig().getGenerateList().contains(path)) {
            return;
        }
        String file;
        if (properties.getClassConfig().getGenerateToProject()) {
            file = properties.getCodePathMap().get(path) + "/" + filename;
            if (new File(file).exists()) {
                file = file + ".copy";
            }
        } else {
            file = getTargetPath() + "generate/" + path + "/" + filename;

        }
        System.out.println("生成文件：" + file);
        FileUtil.writeString(content, file, "utf-8");
    }

    private static String getTargetPath() {
        return FileUtil.getParent(GeneratorService.class.getResource("/").getPath(), 1) + "/";
    }

    public static void appendMethod(String fileName, String content) {
        List<String> appendLines = Arrays.asList(content.split("\n"));
        File file = new File(fileName);
        if (!file.exists()) {
            throw new RuntimeException("文件不存在 " + fileName);
        }
        List<String> lines = FileUtil.readLines(file, "utf-8");
        for (int i = lines.size() - 1; i >= 0; i--) {
            if ("}".equals(lines.get(i).trim())) {
                lines = lines.subList(0, i);
                lines.addAll(appendLines);
                lines.add("\n}");
                break;
            }
        }
        FileUtil.writeUtf8Lines(lines, fileName + "");
    }
}
